﻿using System;
using System.IO;
using System.Net;
using System.Xml;
using System.Diagnostics;

namespace Twitter
{
	/// <summary>
	/// Exposes operations related to users' statuses.
	/// </summary>
	public class Statuses : IStatuses
	{
		AuthenticatedEndpoint twitterEndpoint;
		BotClient client;
		Uri baseUri;

		internal Statuses(
			AuthenticatedEndpoint endpoint,
			Uri baseUri,
			BotClient client)
		{
			this.twitterEndpoint = endpoint;
			this.client = client;
			this.baseUri = baseUri;
		}

		/// <summary>
		/// Updates the status of the authenticated user.
		/// </summary>
		/// <param name="newStatus">New status message.</param>
		/// <remarks>
		/// Functionally equivalent to calling <see cref="BotClient.Execute"/>.
		/// </remarks>
		/// <returns><see langword="true"/> if the status could be updated successfully; <see langword="false"/> otherwise.</returns>
		public bool Update(string newStatus)
		{
			return client.Execute(newStatus);
		}

		/// <summary>
		/// Gets the latest status of the authenticated user.
		/// </summary>
		public Status GetLatest()
		{
			// HACK: the user timeline never authenticates propertly, 
			// and keeps returning forbidden errors. If we go looking 
			// for the friends timeline, where the friend ID is ourselves, 
			// then it works fine :S.
			//http://twitter.com/statuses/user_timeline.xml?count=1

			string uriFormat = "statuses/friends_timeline/{0}.xml";
			string screenName = twitterEndpoint.Credentials.GetCredential(new Uri(baseUri, uriFormat), "").UserName;
			Uri statusUri = new Uri(baseUri, String.Format(uriFormat, screenName));

			Tracer.TraceInformation(typeof(Statuses), "Getting latest status from {0}", statusUri);

			WebRequest request = twitterEndpoint.CreateRequest(statusUri);
			try
			{
				using (WebResponse response = request.GetResponse())
				using (Stream responseStream = response.GetResponseStream())
				{
					XmlReader reader = XmlReader.Create(responseStream);
					foreach (var status in PayloadReader.ReadStatuses(reader))
					{
						Tracer.TraceInformation(typeof(Statuses), "Getting latest status from {0}", statusUri);
						return status;
					}
				}

			}
			catch (WebException wex)
			{
				// TODO: improve error parsing.
				string responseError = new StreamReader(wex.Response.GetResponseStream()).ReadToEnd();
				Tracer.TraceError(typeof(AuthenticatedEndpoint), wex, "Failed to retrieve status from {0}. Response was:\n{1}",
					statusUri,
					responseError);
				throw;
			}
			catch (Exception ex)
			{
				Tracer.TraceError(typeof(AuthenticatedEndpoint), ex, "Failed to retrieve status from {0}.",
					statusUri);
				throw;
			}

			return null;
		}

		/// <summary>
		/// Deletes a status entry given its <paramref name="statusId"/>.
		/// </summary>
		/// <returns><see langword="true"/> if the status could be deleted successfully; <see langword="false"/> otherwise.</returns>
		public bool Delete(string statusId)
		{
			Guard.ArgumentNotNullOrEmptyString(statusId, "statusId");

			// http://twitter.com/statuses/destroy/id.format
			Uri uri = new Uri(baseUri, String.Format("statuses/destroy/{0}.xml", statusId));

			Tracer.TraceInformation(typeof(Statuses), "Deleting status {0}", statusId);

			try
			{
				twitterEndpoint.Execute(uri, HttpMethod.Delete);
				return true;
			}
			catch (Exception ex)
			{
				Tracer.TraceError(typeof(Statuses), ex, "Failed to delete status {0}", statusId);
				return false;
			}
		}
	}
}
